package jmetal.problems.adaboost;

import jmetal.encodings.solutionType.BinaryRealSolutionType;
import jmetal.encodings.solutionType.RealSolutionType;
import jmetal.util.JMException;
import hidra.jmetal.core.Problem;
import hidra.jmetal.core.Solution;
import hidra.jmetal.core.Variable;

public class AdaBoostProblem extends Problem{
	
	private static Adaboost adaboost;
	
	//qtd total de dimensoes = Config.NUMBER_OF_CLASSIFIERS * config.number_of_parameters
	public AdaBoostProblem(String solutionType, 
            Integer numberOfVariables, 
		         Integer numberOfObjectives) throws ClassNotFoundException
	{
		adaboost = new Adaboost();
		adaboost.init(Config.NUMBER_OF_CLASSIFIERS);
		problemName_ = "AdaBoost";
		numberOfVariables_ = numberOfVariables.intValue();
		numberOfObjectives_ = numberOfObjectives;
		lowerLimit_ = new double[numberOfVariables_];
		upperLimit_ = new double[numberOfVariables_];
		for(int i = 0; i < Config.NUMBER_OF_CLASSIFIERS; i++)
		{
			lowerLimit_[Config.CLASSIFIER_PARAMETER_FEATURE + (i*Config.NUMBER_OF_PARAMETERS)] = 1;
			upperLimit_[Config.CLASSIFIER_PARAMETER_FEATURE + (i*Config.NUMBER_OF_PARAMETERS)] = 4;
			lowerLimit_[Config.CLASSIFIER_PARAMETER_HEIGHT + (i*Config.NUMBER_OF_PARAMETERS)] = 1;
			upperLimit_[Config.CLASSIFIER_PARAMETER_HEIGHT + (i*Config.NUMBER_OF_PARAMETERS)] = 24;
			lowerLimit_[Config.CLASSIFIER_PARAMETER_LIMIAR + (i*Config.NUMBER_OF_PARAMETERS)] = -1;
			upperLimit_[Config.CLASSIFIER_PARAMETER_LIMIAR + (i*Config.NUMBER_OF_PARAMETERS)] = 1;
			lowerLimit_[Config.CLASSIFIER_PARAMETER_POLARITY + (i*Config.NUMBER_OF_PARAMETERS)] = -1;
			upperLimit_[Config.CLASSIFIER_PARAMETER_POLARITY + (i*Config.NUMBER_OF_PARAMETERS)] = 1;
			lowerLimit_[Config.CLASSIFIER_PARAMETER_WEIGHT + (i*Config.NUMBER_OF_PARAMETERS)] = 0;
			upperLimit_[Config.CLASSIFIER_PARAMETER_WEIGHT + (i*Config.NUMBER_OF_PARAMETERS)] = 0;
			lowerLimit_[Config.CLASSIFIER_PARAMETER_WIDTH + (i*Config.NUMBER_OF_PARAMETERS)] = 1;
			upperLimit_[Config.CLASSIFIER_PARAMETER_WIDTH + (i*Config.NUMBER_OF_PARAMETERS)] = 24;
			upperLimit_[Config.CLASSIFIER_PARAMETER_XPOSITION + (i*Config.NUMBER_OF_PARAMETERS)] = 23;
			lowerLimit_[Config.CLASSIFIER_PARAMETER_XPOSITION + (i*Config.NUMBER_OF_PARAMETERS)] = 1;
			upperLimit_[Config.CLASSIFIER_PARAMETER_YPOSITION + (i*Config.NUMBER_OF_PARAMETERS)] = 23;
			lowerLimit_[Config.CLASSIFIER_PARAMETER_YPOSITION + (i*Config.NUMBER_OF_PARAMETERS)] = 1;
		}
	    if (solutionType.compareTo("BinaryReal") == 0)
	    	solutionType_ = new BinaryRealSolutionType(this) ;
	    else if (solutionType.compareTo("Real") == 0)
	    	solutionType_ = new RealSolutionType(this) ;
	    else {
	    	System.out.println("Error: solution type " + solutionType + " invalid") ;
	    	System.exit(-1) ;
	    } 
		
	}
	@Override
	public void evaluate(Solution solution) throws JMException {
		Variable[] variables = solution.getDecisionVariables();
		double[] x = new double[numberOfVariables_];
		double[] f = new double[numberOfObjectives_];
		
		for(int i = 0; i < numberOfVariables_; i++)
			x[i] = variables[i].getValue();
		
		WeakClassifier[] classifiers = new WeakClassifier[Config.NUMBER_OF_CLASSIFIERS];
		
		for(int i = 0; i < Config.NUMBER_OF_CLASSIFIERS; i++)
		{
			int offset =(i*Config.NUMBER_OF_PARAMETERS);
			int type = (int)x[Config.CLASSIFIER_PARAMETER_FEATURE + offset];
			int height = (int)x[Config.CLASSIFIER_PARAMETER_HEIGHT + offset];
			int limiar = (int) x[Config.CLASSIFIER_PARAMETER_LIMIAR + offset];
			int width = (int)x[Config.CLASSIFIER_PARAMETER_WIDTH + offset];
			int posX = (int)x[Config.CLASSIFIER_PARAMETER_XPOSITION + offset];
			int posY = (int) x[Config.CLASSIFIER_PARAMETER_YPOSITION + offset];
			int polarity = (int) x[Config.CLASSIFIER_PARAMETER_POLARITY + offset];
			classifiers[i] = new WeakClassifier(type, posX, posY, width, height);
			classifiers[i].setPolarity(polarity);
			classifiers[i].setLimiar(limiar);
			//validando parametros
			classifiers[i].validate();
		}
		
		//avaliando treinamento dos classificadores
		f = adaboost.trainClassifier(classifiers);
		//atualizacao do fitness dos objetivos
		for(int i = 0; i < numberOfObjectives_; i++)
		{
			solution.setObjective(i, f[i]);
		}
		
		
	}
	
}
